#include <getopt.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>

#include <stdexcept>
#include <memory>
#include <string>

#include "sym-name-table.h"
#include "sym-info-table.h"
#include "string-util.h"
#include "log-util.h"
#include "io-util.h"

using std::string;
using std::shared_ptr;
using std::runtime_error;

void sym_add_print_help()
{
    string help_doc =
"sym add OPTIONS SYMBOL-NAME-OPT\n"
"OPTIONS;可取值:\n"
"-L;指定了符号所使用的语言\n"
"-m INFO;指定了符号的介绍文档,若 INFO 以'@'开头,则从文件中读取.\n"
"  程序中对每个 -m 的处理;首先去除两边的空白字符,若以'@'开头,则从文件中读取内容,然后\n"
"  去除内容两边的空格,将处理后的内容追加到之前的缓冲区中;若不以'@'开头,则直接追加到之前\n"
"  的缓冲区中.如: -m'begin',-m'@test.txt' -m'end' 组成的介绍信息是: \n"
"      begin + test.txt文件的内容 + end. \n"
"SYMBOL-NAME-OPT;用来确定一个符号;取决于 -L 的取值;具体如下:\n";
    const auto &langs_vec = SymNameTable::supportLanguages();
    for (const auto &lang_name : langs_vec) {
        SymNameTable *lang_symname_table = SymNameTable::instance(lang_name);
        if (lang_symname_table == NULL)
            throw runtime_error(format("无法创建语言 %s 的实例!",lang_name.c_str()));
        help_doc += lang_name;
        help_doc.append(1,';');
        help_doc += lang_symname_table->help();
        help_doc.append(1,'\n');
    }
    fputs(help_doc.c_str(),stdout);
    return ;
}


int sym_add_main(int argc,char **argv)
{
    SymInfo syminfo;

    string doc;
    int getopt_ret;
    optind = 0;
    opterr = 0;
    while ((getopt_ret = getopt(argc,argv,"-L:m:h")) != -1) {
        switch (getopt_ret) {
        case 'L': {
            if (!syminfo.language().empty()) {
                LOGW("当前语言设置 %s 将会覆盖上次 -L 选项指定的参数 %s!",
                     optarg,
                     syminfo.language().c_str());
            }
            syminfo.setLanguage(optarg);
        }   break;
        case 'm': {
            string m_opt_val {optarg};
            trim(m_opt_val);
            if (m_opt_val.empty()) {
                LOGW("-m 选项参数不合法;全部为空白字符");
                break;
            }
            if (m_opt_val.front() == '@') {
                const char *filename = m_opt_val.c_str();
                ++filename;
                string file_content;
                read(filename,file_content);
                trim(file_content);
                doc += file_content;
            } else {
                doc += m_opt_val;
            }
            doc.append(1,'\n');
        }   break;
        case 'h':
            sym_add_print_help();
            return 0;
        default:
            break;
        }
    }
    syminfo.setDoc(doc);

    auto *table_p = SymNameTable::instance(syminfo.language());
    if (table_p == NULL) {
        LOGE("无法实例化语言 %s!可能其不存在,或者内存不足.",syminfo.language().c_str());
        return 1;
    }
    auto symname_p = table_p->getSymName(argc,argv);

    SymInfoTable &sym_info_table = SymInfoTable::instance();
    sym_info_table.insert(syminfo);

    try {
        table_p->add(syminfo.id(),symname_p);
    } catch (...) {
        sym_info_table.remove(syminfo.id());
        throw;
    }
    return 0;
}


